﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Unscrambler.Views;
using System.Windows.Input;
using System.Windows;
using System.Windows.Media;
using System.Windows.Controls;

namespace Unscrambler.Helpers
{
    public class TileManipulator : TileHelperBase
    {
        private IGameboardView _gameboard;
        private UIElement last;

        public TileManipulator(IGameboardView gameboard)
        {
            if (gameboard == null)
            {
                throw new ArgumentNullException("Gameboard cannot be null");
            }
            _gameboard = gameboard;
        }

        public void HandleTileManipulation()
        {
            _gameboard.ManipulationStarting += Gameboard_ManipulationStarting;
            _gameboard.ManipulationDelta += Gameboard_ManipulationDelta;
            _gameboard.ManipulationInertiaStarting += Gameboard_ManipulationInertiaStarting;
            _gameboard.ManipulationCompleted += new EventHandler<ManipulationCompletedEventArgs>(Gameboard_ManipulationCompleted);
        }

        void Gameboard_ManipulationInertiaStarting(object sender, ManipulationInertiaStartingEventArgs e)
        {

            // Decrease the velocity of the Rectangle's movement by 
            // 10 inches per second every second.
            // (15 inches * 96 DIPS per inch / 1000ms^2)
            e.TranslationBehavior = new InertiaTranslationBehavior()
            {
                InitialVelocity = e.InitialVelocities.LinearVelocity,
                DesiredDeceleration = 15.0 * 96.0 / (1000.0 * 1000.0)
            };
            e.Handled = true;

            e.RotationBehavior = new InertiaRotationBehavior();
            e.RotationBehavior.InitialVelocity = e.InitialVelocities.AngularVelocity;
            // 7200 degrees per second squared.
            e.RotationBehavior.DesiredDeceleration = 7200 / (1000.0 * 1000.0);
        }

        void Gameboard_ManipulationCompleted(object sender, ManipulationCompletedEventArgs e)
        {
            UIElement itemManipulated = e.OriginalSource as UIElement;
            if (itemManipulated != null)
            {
                _gameboard.UpdateAnswer(itemManipulated);
            }
        }

        

        void Gameboard_ManipulationStarting(object sender, ManipulationStartingEventArgs e)
        {
            e.ManipulationContainer = _gameboard.ScramblePanel;

        }

        void Gameboard_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
        {
            UIElement itemManipulated = e.OriginalSource as UIElement;
            if (itemManipulated != null)
            {

                AdjustZIndexOfManipulatedItem(itemManipulated);
                ApplyRotationDelta(itemManipulated, e.DeltaManipulation.Rotation);
                
                // apply translation 
                TranslateTransform translateTransform = GetTranslateTransformFromUIElement(itemManipulated);
                translateTransform.X += e.DeltaManipulation.Translation.X;
                translateTransform.Y += e.DeltaManipulation.Translation.Y;
                Rect containerBounds = new Rect(((FrameworkElement)e.ManipulationContainer).RenderSize);
                Rect objectBounds = itemManipulated.RenderTransform.TransformBounds(new Rect(itemManipulated.RenderSize));

                if (e.IsInertial && !containerBounds.Contains(objectBounds))
                {
                    e.Complete();
                    //Report that we have gone over our boundary 
                    e.ReportBoundaryFeedback(e.DeltaManipulation);
                    e.Handled = true;
                    ForceElementBackInBoundsIfItWentOut(translateTransform, ref containerBounds, ref objectBounds);
                }
            }
        }

        private static void ForceElementBackInBoundsIfItWentOut(TranslateTransform translateTransform, ref Rect containerBounds, ref Rect objectBounds)
        {
            if (objectBounds.Left < containerBounds.Left)
            {
                translateTransform.X = containerBounds.Left;
            }
            if (objectBounds.Right > containerBounds.Right)
            {
                translateTransform.X = containerBounds.Right - objectBounds.Width;
            }
            if (objectBounds.Top < containerBounds.Top)
            {
                translateTransform.Y = containerBounds.Top;
            }
            if (objectBounds.Bottom > containerBounds.Bottom)
            {
                translateTransform.Y = containerBounds.Bottom - objectBounds.Height;
            }
        }

        private void ApplyRotationDelta(UIElement itemManipulated, double delta)
        {
            // the center never changes in this sample, although we always compute it.
            Point center = new Point(itemManipulated.RenderSize.Width / 2.0, itemManipulated.RenderSize.Height / 2.0);
            RotateTransform rotation = GetRotateTransformFromUIElement(itemManipulated);

            // apply the rotation at the center of the rectangle if it has changed
            rotation.CenterX = center.X;
            rotation.CenterY = center.Y;
            rotation.Angle += delta;
        }

        private void AdjustZIndexOfManipulatedItem(UIElement itemManipulated)
        {
            if (last != null) Canvas.SetZIndex(last, 0);
            Canvas.SetZIndex(itemManipulated, 2);
            last = itemManipulated;
        }
    }
}
